package com.baturu.vin.benz.service.impl;

import com.baturu.carvin.service.impl.AppConfigLoader;
import com.baturu.vin.benz.dal.dao.BenzPartsMappingDAO;
import com.baturu.vin.benz.dal.dao.BenzSaDAO;
import com.baturu.vin.benz.dal.dao.BenzVinCarTypeInfoDAO;
import com.baturu.vin.benz.dto.*;
import com.baturu.vin.benz.service.impl.util.BenzStringUtil;
import com.baturu.vin.dto.EPCAnalyserEnum;
import com.baturu.vin.dto.EPCPartsDTO;
import com.baturu.vin.dto.EPCPartsImageDTO;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toMap;

/**
 * 奔驰vin码和配件编码解析器
 *
 * @author 蒋鑫磊
 * @Time 2016/11/28.
 */
@Slf4j
@Service("benzEPCPartsService")
public class BenzEPCPartsService implements InitializingBean {


    private static final Pattern GEARS_NUM_PATTERN = Pattern.compile("(\\d)+(\\s[档])");
    private static final Pattern DISPLACEMENT_PATTERN = Pattern.compile("([0-9.]+)");

    @Autowired
    private BenzCarTypeInfoService benzCarTypeInfoService;
    @Autowired
    private AppConfigLoader appConfigLoader;
    @Autowired
    private BenzPartsMappingDAO benzPartsMappingDAO;
    @Autowired
    private BenzVinCarTypeInfoDAO vinCarTypeInfoDAO;
    @Autowired
    private BenzSaDAO benzSaDAO;

    private static Map<String, List<BenzSaDTO>> displacementMap;
    private static Map<String, List<BenzSaDTO>> transmissionMap;
    private static Set<String> displacementSet;
    private static Set<String> transmissionSet;

    @Override
    public void afterPropertiesSet() {
        //获取sa的注释,如果没有则获取
        List<BenzSaDTO> benzSaDTOS = benzSaDAO.queryAllSaDescription();
        //加入sacode是为了之后的排量和变速箱做准备,但会导致数据量很大...因此优先处理掉sacode字段
        displacementMap = benzSaDTOS.stream().filter(p -> StringUtils.isNotBlank(p.getAdesc())).filter(p -> p.getAdesc().contains("排量")).collect(groupingBy(BenzSaDTO::getSaCode));
        displacementSet = displacementMap.keySet();
        transmissionMap = benzSaDTOS.stream().filter(p -> StringUtils.isNotBlank(p.getAdesc())).filter(p -> p.getAdesc().contains("变速")).collect(groupingBy(BenzSaDTO::getSaCode));
        transmissionSet = transmissionMap.keySet();
    }


    public BenzVinInfoDTO getBenzVinCarTypeInfo(String vinCode) {
        // 获取vin对应的 车信息 和 SA代码
        BenzVinFinInfoDTO benzVinFinInfoDTO = benzCarTypeInfoService.getFinInfo(vinCode);
        if (benzVinFinInfoDTO == null) {
            return null;
        }
        Set<String> saCodeSet = benzCarTypeInfoService.buildSACode(benzVinFinInfoDTO);
        //获取发动机 波箱 前轴 后轴 转向系 等信息
        BenzVinInfoDTO benzVinInfoDTO = benzCarTypeInfoService.buildCarTypeInfo(benzVinFinInfoDTO);
        if (benzVinInfoDTO == null) {
            log.info("没有在dc_rtype1_v_{}找到相应数据: {}", benzVinFinInfoDTO.getDbName(), vinCode);
            return null;
        }
        // 完善车的SA代码
        modifySaCode(saCodeSet, benzVinInfoDTO);

        // 根据vin的底盘号等信息 获取 catNum,
        String appInf = BenzStringUtil.buildAppInf(benzVinFinInfoDTO.getLocation());
        Map<String, BenzPartCatInfoDTO> catInfoMap = benzCarTypeInfoService.getCatInfoMap(benzVinInfoDTO, appInf);
        Map<String, BenzPartCatInfoDTO> catInfoMapByCatNum = catInfoMap.keySet().stream().collect(toMap(e -> catInfoMap.get(e).getCatalog().trim(), catInfoMap::get, (v1, v2) -> v1));
        List<String> catNums = catInfoMap.keySet().stream().map(p -> catInfoMap.get(p).getCatalog().trim()).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(catNums)) {
            return null;
        }
        String vehClass = null;
        for (String s : catInfoMap.keySet()) {
            vehClass = catInfoMap.get(s).getClassNo();
        }
        if (StringUtils.isBlank(vehClass)) {
            return null;
        }

        if (!rebuildVinCarTypeInfo(benzVinInfoDTO)) {
            return null;
        }

        //排量,变速箱类型,档位
        dealDisplacementAndTransInfo(saCodeSet, benzVinInfoDTO);

        // 转向系  设定2 6 为右肽 其他情况下不填
        String vehSteering = StringUtils.startsWithAny(benzVinInfoDTO.getChassIdent(), "2", "6") ? "R" : "";
        benzVinInfoDTO.setVehSteering(vehSteering);
        benzVinInfoDTO.setSaCodeSet(saCodeSet);
        benzVinInfoDTO.setCatInfoMap(catInfoMap);
        benzVinInfoDTO.setCatInfoMapByCatNum(catInfoMapByCatNum);
        benzVinInfoDTO.setCatNums(catNums);
        benzVinInfoDTO.setVehClass(vehClass);
        benzVinInfoDTO.setVinCode(vinCode);
        return benzVinInfoDTO;
    }

    private List<String> build(List<BenzSaDTO> dtos, Predicate<BenzSaDTO> predicate) {
        return dtos.stream().filter(predicate).map(BenzSaDTO::getAdesc).collect(Collectors.toList());
    }

    private Set<String> buildInfo(Set<String> disresult, Set<String> vinTypes, BenzVinInfoDTO benzVinInfoDTO, Map<String, List<BenzSaDTO>> displacementMap) {
        Set<String> result = Sets.newHashSet();
        if (CollectionUtils.isEmpty(disresult)) {
            return result;
        }
        Set<String> descWithoutType = Sets.newHashSet();
        Set<String> descWithoutDate = Sets.newHashSet();
        List<BenzSaDTO> dtos = disresult.stream()
                .map(displacementMap::get).flatMap(Collection::stream).collect(Collectors.toList());
        descWithoutDate.addAll(build(dtos, dto -> StringUtils.isBlank(dto.getAdate())));
        descWithoutType.addAll(
                build(dtos, dto ->
                        StringUtils.isNotBlank(dto.getAdate())
                                && (Integer.valueOf(benzVinInfoDTO.getAdate()) >= Integer.valueOf(dto.getAdate()))
                                && StringUtils.isBlank(dto.getType()))
        );

        result.addAll(
                build(dtos, dto -> StringUtils.isNotBlank(dto.getAdate())
                        && Integer.valueOf(benzVinInfoDTO.getAdate()) >= Integer.valueOf(dto.getAdate())
                        && StringUtils.isNotBlank(dto.getType())
                        && vinTypes.contains(dto.getType())));

        if (CollectionUtils.isEmpty(result)) {
            Set<String> desc = CollectionUtils.isNotEmpty(descWithoutType) ? descWithoutType : descWithoutDate;
            result.addAll(desc);
        }
        return result;
    }

    public void dealDisplacementAndTransInfo(Set<String> saCodeSet, BenzVinInfoDTO benzVinInfoDTO) {

        //排量,变速箱类型,档位
        Set<String> vinTypes = Sets.newHashSet();
        vinTypes.addAll(dealAllType(benzVinInfoDTO.getChassbm()));
        vinTypes.addAll(dealAllType(benzVinInfoDTO.getEngine()));
        vinTypes.addAll(dealAllType(benzVinInfoDTO.getTransmission()));
        Set<String> disresult = Sets.newHashSet(displacementSet);
        disresult.retainAll(saCodeSet);
        Set<String> disInfo = buildInfo(disresult, vinTypes, benzVinInfoDTO, displacementMap);

        Set<String> transresult = Sets.newHashSet(transmissionSet);
        transresult.retainAll(saCodeSet);
        Set<String> transInfo = buildInfo(transresult, vinTypes, benzVinInfoDTO, transmissionMap);

        String displacement = "";

        if (CollectionUtils.isNotEmpty(disInfo)) {
            for (String s : disInfo) {
                Matcher matcher = DISPLACEMENT_PATTERN.matcher(s);
                if (matcher.find()) {
                    displacement = matcher.group(0);
                    break;
                }
            }
        }

        String transmissionType = "";
        String gearsNum = "";

        if (CollectionUtils.isNotEmpty(transInfo)) {
            for (String s : transInfo) {
                if (s.contains("自动")) {
                    transmissionType = "自动";
                } else if (s.contains("手动")) {
                    transmissionType = "手动";
                }


                Matcher matcher = GEARS_NUM_PATTERN.matcher(s);
                if (matcher.find()) {
                    gearsNum = matcher.group(1) + "档";
                    break;
                }
            }
        }
        benzVinInfoDTO.setDisplacement(displacement);
        benzVinInfoDTO.setTransmissionType(transmissionType);
        benzVinInfoDTO.setGearsNum(gearsNum);
    }

    public boolean rebuildVinCarTypeInfo(BenzVinInfoDTO benzVinInfoDTO) {
        if (benzVinInfoDTO == null) {
            return false;
        }
        String tempDate = BenzStringUtil.getTempDate(benzVinInfoDTO.getReleaseDate(), benzVinInfoDTO.getDeliveryDate());
        if (StringUtils.isBlank(tempDate)) {
            log.debug("没有日期信息");
            return false;
        }
        String dateyear = tempDate.substring(0, 4);
        String country = BenzStringUtil.getCountry(benzVinInfoDTO.getWhc());
        if (StringUtils.isBlank(country)) {
            log.debug("国家地区转换出错");
            return false;
        }
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
        try {
            Date date = df.parse(tempDate);
            benzVinInfoDTO.setProTime(date);
        } catch (Exception e) {
            log.error("analyseVinCode时间转化出错", e);
        }
        benzVinInfoDTO.setShortEngine(BenzStringUtil.shortString(benzVinInfoDTO.getEngine()));
        benzVinInfoDTO.setShortTransmission(BenzStringUtil.shortString(benzVinInfoDTO.getTransmission()));
        benzVinInfoDTO.setDateyear(dateyear);
        benzVinInfoDTO.setAdate(tempDate);
        benzVinInfoDTO.setCountry(country);
        return true;
    }

    private Set<String> dealAllType(String str) {
        Set<String> type = Sets.newHashSet();
        if (str != null) {
            str += "       ";
            type.add(str.substring(0, 3));
            type.add(str.substring(0, 3) + "." + str.substring(3, 4));
            type.add(str.substring(0, 3) + "." + str.substring(3, 5));
            type.add(str.substring(0, 3) + "." + str.substring(3, 6));
        }
        return type;
    }

    List<EPCPartsDTO> fillExtraNameCodeRelation(Set<String> btrPartsNames, BenzVinInfoDTO benzVinInfoDTO) {
        List<EPCPartsDTO> epcPartsDTOs = Lists.newArrayList();
        if (CollectionUtils.isEmpty(btrPartsNames) || benzVinInfoDTO == null) {
            return Collections.emptyList();
        }
        if (StringUtils.isBlank(benzVinInfoDTO.getVehClass()) ||
                !("1".equals(benzVinInfoDTO.getVehClass()) || "2".equals(benzVinInfoDTO.getVehClass()) || "3".equals(benzVinInfoDTO.getVehClass()) || "F".equals(benzVinInfoDTO.getVehClass()))) {
            return Collections.emptyList();
        }
        List<BenzPartsMappingDTO> extraRelationDTOs = benzPartsMappingDAO.findRelationByExtraPartsName(btrPartsNames);
        if (CollectionUtils.isEmpty(extraRelationDTOs)) {
            return Collections.emptyList();
        }
        Map<String, List<BenzPartsMappingDTO>> relationMaps = extraRelationDTOs.stream().collect(groupingBy(BenzPartsMappingDTO::getBtrPartsName));
        for (String partsName : relationMaps.keySet()) {
            List<BenzPartsMappingDTO> relationDTOs = relationMaps.get(partsName);
            if (CollectionUtils.isEmpty(relationDTOs)) {
                continue;
            }
            Map<String, List<BenzPartsMappingDTO>> codeMaps = relationDTOs.stream().collect(groupingBy(BenzPartsMappingDTO::getPartsCode));
            switch (partsName) {
                case "变速箱油":
                    if (StringUtils.equals(benzVinInfoDTO.getVehClass(), "F")) {
                        List<BenzPartsMappingDTO> dtos = codeMaps.get("A0019895103");
                        fillEpcPartsDTOs(partsName, dtos.get(0), epcPartsDTOs);
                        continue;
                    }
                    String shortTransmission = benzVinInfoDTO.getShortTransmission();
                    if (StringUtils.isNotBlank(shortTransmission) && shortTransmission.length() > 3) {
                        switch (shortTransmission.substring(0, 4)) {
                            case "7226": {
                                List<BenzPartsMappingDTO> dtos = codeMaps.get("A0019892103");
                                fillEpcPartsDTOs(partsName, dtos.get(0), epcPartsDTOs);
                                break;
                            }
                            case "7228": {
                                List<BenzPartsMappingDTO> dtos = codeMaps.get("A0019894603");
                                fillEpcPartsDTOs(partsName, dtos.get(0), epcPartsDTOs);
                                break;
                            }
                            case "7229": {
                                if ("20100618".compareTo(benzVinInfoDTO.getAdate()) >= 0) {
                                    List<BenzPartsMappingDTO> dtos = codeMaps.get("A0019896803");
                                    fillEpcPartsDTOs(partsName, dtos.get(0), epcPartsDTOs);
                                } else if ("20100618".compareTo(benzVinInfoDTO.getAdate()) < 0) {
                                    List<BenzPartsMappingDTO> anotherDtos = codeMaps.get("A0019897803");
                                    fillEpcPartsDTOs(partsName, anotherDtos.get(0), epcPartsDTOs);
                                }
                                break;
                            }
                            default:
                        }
                        switch (shortTransmission.substring(0, 3)) {
                            case "724": {
                                List<BenzPartsMappingDTO> dtos = codeMaps.get("A0019898503");
                                fillEpcPartsDTOs(partsName, dtos.get(0), epcPartsDTOs);
                                break;
                            }
                            case "725": {
                                List<BenzPartsMappingDTO> dtos = codeMaps.get("A0019899203");
                                fillEpcPartsDTOs(partsName, dtos.get(0), epcPartsDTOs);
                                break;
                            }
                            default:
                        }
                    }
                    break;
                case "机油": {
                    List<BenzPartsMappingDTO> dtos = codeMaps.get("A0009898301");
                    String shortEngine = benzVinInfoDTO.getShortEngine();
                    if (StringUtils.isNotBlank(shortEngine) && "6".equalsIgnoreCase(shortEngine.substring(0, 1))) {
                        dtos = codeMaps.get("A0009899701");
                    }
                    String salesDes = vinCarTypeInfoDAO.queryAMGCarType(benzVinInfoDTO.getChassbm().substring(0, 3), benzVinInfoDTO.getChassbm().substring(3, 6));
                    if (StringUtils.isNotBlank(salesDes)) {
                        dtos = codeMaps.get("A0009898301UCX6");
                    }
                    fillEpcPartsDTOs(partsName, dtos.get(0), epcPartsDTOs);
                    break;
                }
                case "防冻液": {
                    String dateyear = benzVinInfoDTO.getDateyear();
                    List<BenzPartsMappingDTO> dtos = codeMaps.get("A0009892825");
                    if ("2013".compareTo(dateyear) >= 0) {
                        dtos = codeMaps.get("A0009890825");
                    }
                    fillEpcPartsDTOs(partsName, dtos.get(0), epcPartsDTOs);
                    break;
                }
                case "差速器油": {
                    List<BenzPartsMappingDTO> dtos = codeMaps.get("A0019893303");
                    String salesDes = vinCarTypeInfoDAO.queryAMGCarType(benzVinInfoDTO.getChassbm().substring(0, 3), benzVinInfoDTO.getChassbm().substring(3, 6));
                    if (StringUtils.isNotBlank(salesDes)) {
                        dtos = codeMaps.get("A0019895203");
                    }
                    fillEpcPartsDTOs(partsName, dtos.get(0), epcPartsDTOs);
                    break;
                }
                case "燃油添加剂": {
                    List<BenzPartsMappingDTO> dtos = codeMaps.get("A0009892545");
                    String shortEngine = benzVinInfoDTO.getShortEngine();
                    if (StringUtils.isNotBlank(shortEngine) && "6".equalsIgnoreCase(shortEngine.substring(0, 1))) {
                        dtos = codeMaps.get("A0009893045");
                    }
                    fillEpcPartsDTOs(partsName, dtos.get(0), epcPartsDTOs);
                    break;
                }
                default:
                    for (BenzPartsMappingDTO relationDTO : relationDTOs) {
                        fillEpcPartsDTOs(partsName, relationDTO, epcPartsDTOs);
                    }
                    break;
            }
        }
        return epcPartsDTOs;
    }

    List<EPCPartsDTO> fillExtraCodeRelation(Set<String> partsCodes, BenzVinInfoDTO benzVinInfoDTO) {
        List<EPCPartsDTO> epcPartsDTOs = Lists.newArrayList();
        if (CollectionUtils.isEmpty(partsCodes) || benzVinInfoDTO == null) {
            return Collections.emptyList();
        }
        if (StringUtils.isBlank(benzVinInfoDTO.getVehClass()) ||
                !("1".equals(benzVinInfoDTO.getVehClass()) || "2".equals(benzVinInfoDTO.getVehClass()))) {
            return Collections.emptyList();
        }
        List<BenzPartsMappingDTO> extraRelationDTOs = benzPartsMappingDAO.findRelationByExtraPartsCode(partsCodes);
        if (CollectionUtils.isEmpty(extraRelationDTOs)) {
            return Collections.emptyList();
        }
        Map<String, List<BenzPartsMappingDTO>> codeMaps = extraRelationDTOs.stream().collect(groupingBy(BenzPartsMappingDTO::getPartsCode));
        for (String partsCode : codeMaps.keySet()) {
            List<BenzPartsMappingDTO> benzPartsMappingDTOS = codeMaps.get(partsCode);
            if (CollectionUtils.isEmpty(benzPartsMappingDTOS)) {
                continue;
            }
            fillEpcPartsDTOs(null, benzPartsMappingDTOS.get(0), epcPartsDTOs);
        }
        return epcPartsDTOs;
    }

    private void fillEpcPartsDTOs(String btrPartsName, BenzPartsMappingDTO benzPartsMappingDTO, List<EPCPartsDTO> epcPartsDTOs) {
        if (benzPartsMappingDTO == null) {
            return;
        }
        EPCPartsDTO epcPartsDTO = new EPCPartsDTO();
        epcPartsDTO.setBtrPartsName(btrPartsName);
        String partsCode = benzPartsMappingDTO.getPartsCode();
        epcPartsDTO.setPartsCode(partsCode);
        if (benzPartsMappingDTO.isHasImg()) {
            EPCPartsImageDTO epcPartsImageDTO = new EPCPartsImageDTO();
            epcPartsImageDTO.setImageName(partsCode);
            String imageUrl = "oil/" + partsCode + ".png";
            String imgPath = appConfigLoader.getEPCPartsImageFullUrl(EPCAnalyserEnum.BENZ, imageUrl);
            epcPartsImageDTO.setImageUrl(imgPath);
            epcPartsDTO.setEpcPartsImageDTOs(Lists.newArrayList(epcPartsImageDTO));
        }
        epcPartsDTOs.add(epcPartsDTO);
    }

    private void modifySaCode(Set<String> saCode, BenzVinInfoDTO benzVinInfoDTO) {
        StringBuilder additionalCodes = new StringBuilder();
        additionalCodes.append(buildSzPaint(benzVinInfoDTO.getPaint1()));
        additionalCodes.append(buildSzPaint(benzVinInfoDTO.getPaint2()));
        additionalCodes.append(buildSzPaint(benzVinInfoDTO.getPaint3()));
        additionalCodes.append(buildSzPaint(benzVinInfoDTO.getPaint4()));
        additionalCodes.append(buildSzPaint(benzVinInfoDTO.getPaint5()));

        String szTrim = benzVinInfoDTO.getInterior();
        if (szTrim != null && szTrim.length() > 0 && !szTrim.startsWith("  ")) {
            szTrim = szTrim.trim();
            if (szTrim.length() < 4) {
                szTrim += "A";
            }
            additionalCodes.append(szTrim);
        }
        String s = additionalCodes.toString();
        if (StringUtils.isNotBlank(s)) {
            BenzStringUtil.addCode(saCode, s);
        }
    }

    private String buildSzPaint(String szPaint) {
        String blankPad = "    ";
        if (StringUtils.isNotBlank(szPaint)) {
            if (szPaint.length() < 4) {
                return szPaint + blankPad.substring(0, 4 - szPaint.length());
            }
            return szPaint;
        }
        return "";
    }

}
